package com.hub.realtime.resource.domain;


import java.io.File;
import java.io.IOException;
import java.util.*;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.hub.realtime.common.core.domain.model.ClusterInfo;
import com.hub.realtime.common.enums.GitAuthorizedError;
import com.hub.realtime.common.utils.hadoop.HdfsUtil;
import com.hub.realtime.common.utils.password.PasswordUtil;
import lombok.Getter;
import lombok.Setter;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import com.hub.realtime.common.annotation.Excel;
import com.hub.realtime.common.core.domain.BaseEntity;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.transport.CredentialsProvider;
import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider;

/**
 * 【请填写功能名称】对象 res_flink_project
 * 主要用于编译git项目
 *
 * @author wupeng
 * @date 2022-01-09
 */
@Setter
@Getter
@TableName("res_flink_project")
public class ResFlinkProject extends BaseEntity<ResFlinkProject> {
    private static final long serialVersionUID = 1L;

    /**
     * 主键ID
     */
    @TableId(value = "id", type = IdType.AUTO)
    private Long id;

    /**
     * 名称
     */
    @TableField("name")
    @Excel(name = "名称")
    private String name;

    /**
     * git地址
     */
    @Excel(name = "git地址")
    @TableField("url")
    private String url;

    /**
     * 分支名称
     */
    @Excel(name = "分支名称")
    @TableField("branches")
    private String branches;

    /**
     * 用户名
     */
    @Excel(name = "用户名")
    @TableField("username")
    private String username;

    /**
     * 密码
     */
    @Excel(name = "密码")
    @TableField("password")
    private String password;

    /**
     * pom存放
     */
    @Excel(name = "pom存放")
    @TableField("pom")
    private String pom;

    /**
     * 上次构建时间
     */
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @TableField("lastbuild")
    @Excel(name = "上次构建时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
    private Date lastbuild;

    /**
     * 描述信息
     */
    @Excel(name = "描述信息")
    @TableField("description")
    private String description;

    @TableField("buildstate")
    /** 构建状态0 未构建 1构建成功 2构建失败 */
    @Excel(name = "构建状态0 未构建 1构建中 2构建失败")
    private Long buildstate;

    @TableField("user_id")
    /** 用户id */
    @Excel(name = "用户id")
    private Long userId;

    @TableField("application_id")
    /** 所属的项目id */
    @Excel(name = "所属的项目id")
    private Long applicationId;

    @TableField("uid")
    private String uid;

    @TableField("path")
    private String path;

    @TableField("remark")
    private String remark;

    @TableField(exist = false)
    private String appSource;

    @TableField("sessionId")
    private String sessionId;


    @TableField("cluster_id")
    private Long clusterId;


    @JsonIgnore
    public File getGitRepository() {
        File home = getAppSource();
        return new File(home, ".git");
    }

    @JsonIgnore
    public void delete() throws IOException {
        File file = getGitRepository();
        if (file.exists())
            FileUtils.deleteDirectory(file);
    }

    @JsonIgnore
    public String getRootName(){
        return url.replaceAll(".*/|\\.git|\\.svn", "");
    }


    @JsonIgnore
    public List<String> getAllBranches() {
        try {
            Collection<Ref> refList;
            if (PasswordUtil.userNameAndPasswordCheck(username, password)) {
                UsernamePasswordCredentialsProvider pro = new UsernamePasswordCredentialsProvider(username, password);
                refList = Git.lsRemoteRepository().setRemote(url).setCredentialsProvider(pro).call();
            } else {
                refList = Git.lsRemoteRepository().setRemote(url).call();
            }
            List<String> branchList = new ArrayList<>(4);
            for (Ref ref : refList) {
                String refName = ref.getName();
                if (refName.startsWith("refs/heads/")) {
                    String branchName = refName.replace("refs/heads/", "");
                    branchList.add(branchName);
                }
            }
            return branchList;
        } catch (Exception ignored) {
        }
        return Collections.emptyList();
    }


    @JsonIgnore
    public GitAuthorizedError gitCheck() {
        try {
            if (PasswordUtil.userNameAndPasswordCheck(username, password)) {
                UsernamePasswordCredentialsProvider credentialsProvider = new UsernamePasswordCredentialsProvider(username, password);
                Git.lsRemoteRepository().setRemote(url).setCredentialsProvider(credentialsProvider).call();
            } else {
                Git.lsRemoteRepository().setRemote(url).call();
            }
            return GitAuthorizedError.SUCCESS;
        } catch (Exception e) {
            String err = e.getMessage();
            if (err.contains("not authorized")) {
                return GitAuthorizedError.ERROR;
            } else if (err.contains("Authentication is required")) {
                return GitAuthorizedError.REQUIRED;
            }
            return GitAuthorizedError.UNKNOW;
        }
    }


    /**
     * 如果检查到项目已经存在被clone过,则先删除,
     * 主要是解决: 如果最新拉取的代码里有文件删除等,本地不会自动删除
     * 可能会引发不可预知的错误
     */
    public void cleanCloned(ClusterInfo clusterInfo, String distPath) throws IOException {
        if (isCloned()) {
            FileUtils.deleteDirectory(getAppSource());
            if (HdfsUtil.exists(clusterInfo, distPath)) {
                HdfsUtil.delete(clusterInfo, distPath);
            }
        }
    }

    @JsonIgnore
    public boolean isCloned() {
        File repository = getGitRepository();
        return repository.exists();
    }

    @JsonIgnore
    public File getAppSource() {
        File sourcePath = new File(appSource);
        if (!sourcePath.exists()) {
            sourcePath.mkdirs();
        }
        if (sourcePath.isFile()) {
            throw new IllegalArgumentException("git 目录必须是文件夹");
        }
        String branches = StringUtils.isEmpty(this.getBranches()) ? "main" : this.getBranches();
        String rootName = url.replaceAll(".*/|\\.git|\\.svn", "");
        String fullName = rootName.concat("-").concat(branches);
        String path = String.format("%s/%s/%s", sourcePath.getAbsolutePath(), getName(), fullName);
        return new File(path);
    }


    @JsonIgnore
    public List<String> getMavenBuildCmd() {
        String buildHome = this.getAppSource().getAbsolutePath();
        return Arrays.asList("cd ".concat(buildHome), "mvn clean install -DskipTests");
    }

    @JsonIgnore
    public String getLog4BuildStart() {
        return String.format(
                "%sproject : %s\nbranches: %s\ncommand : %s\n\n",
                getLogHeader("maven install"),
                getName(),
                getBranches(),
                getMavenBuildCmd()
        );
    }

    @JsonIgnore
    private String getLogHeader(String header) {
        return "---------------------------------[ " + header + " ]---------------------------------\n";
    }

    @JsonIgnore
    public String getLog4CloneStart() {
        return String.format(
                "%sproject  : %s\nbranches : %s\nworkspace: %s\n\n",
                getLogHeader("git clone"),
                getName(),
                getBranches(),
                getAppSource()
        );
    }

    @JsonIgnore
    public CredentialsProvider getCredentialsProvider() {
        return new UsernamePasswordCredentialsProvider(this.username, this.password);
    }



}
